package pub.tbc.mybatis.assist.plugin;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Properties;

/**
 * 用于SQL执行时间的记录、统计
 *
 * @author tbc on 2017/5/14.
 */
@Slf4j
@Intercepts(
        value = {
                @Signature(
                        type = Executor.class,      // 确定要拦截的对象
                        method = "update",          // 确定要拦截的方法
                        args = {MappedStatement.class, Object.class}    // 拦截方法的参数
                ),
                @Signature(
                        type = Executor.class,
                        method = "query",
                        args = {
                                MappedStatement.class,
                                Object.class,
                                RowBounds.class,
                                ResultHandler.class,
                                CacheKey.class,
                                BoundSql.class
                        }
                ),
                @Signature(
                        type = Executor.class,
                        method = "query",
                        args = {
                                MappedStatement.class,
                                Object.class,
                                RowBounds.class,
                                ResultHandler.class
                        }
                )
        }
)
public class TimeInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.debug("Interceptor: {}, invocation: {}", getClass(), invocation);

        Object target = invocation.getTarget();
        Object result = null;
        if (target instanceof Executor) {
            LocalDateTime startTime = LocalDateTime.now();
            log.debug("[开始计时] startTime : {}", startTime);

            Method method = invocation.getMethod();
            Object[] args = invocation.getArgs();
            log.debug("args: {}", args);
            MappedStatement ms = (MappedStatement) args[0];

            /* 执行方法 */
            result = invocation.proceed();

            LocalDateTime endTime = LocalDateTime.now();
            log.debug("[结束计时] endTime : {}", endTime);

            log.info(
                    "[执行时间] => execute [{}] cost [{}] ms, SqlId => {}",
                    method.getName(),
                    Duration.between(startTime, endTime).toMillis(),
                    ms.getId()
            );
        }
        return result;
    }

    @Override
    public Object plugin(Object target) {
        log.debug("[添加动态代理对象] interceptor: {}, target: {}", getClass().getSimpleName(), target.getClass().getSimpleName());
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        log.debug("set properties : {}", properties);
    }
}
